package spider.netty.server.handler;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import spider.netty.entity.Message;
import spider.netty.node.NettyChannelNodeManager;
import spider.zookeeper.util.StringUtils;

import java.nio.charset.Charset;

/**
 * WebSocketServerHandler
 *
 * @author Archx[archx@foxmail.com]
 * @date 2017/4/8.
 */
@ChannelHandler.Sharable
public class WebSocketServerHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketServerHandler.class);

    private NettyChannelNodeManager nettyChannelNodeManager;

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame msg) throws Exception {
        ByteBuf content = msg.content();
        String text = content.toString(Charset.forName("utf-8"));

        logger.info("> Message : [ {} ]", text);

        Channel incoming = ctx.channel();
        Message message = JSON.parseObject(text, Message.class);

        Message.Action action = message.getAction();
        if (action == Message.Action.Login) {
            String uid = message.getUid();
            nettyChannelNodeManager.register(uid, incoming);

            JSONObject resp = new JSONObject();
            resp.put("code", 0);
            resp.put("uid", uid);
            resp.put("action", Message.Action.Login);
            resp.put("nodeId", nettyChannelNodeManager.getNodeId());

            ctx.pipeline().writeAndFlush(new TextWebSocketFrame(resp.toJSONString()));
        } else if (action == Message.Action.Talk) {
            nettyChannelNodeManager.writeAndFlush(new TextWebSocketFrame(text), message.getTargetUid());
        } else if (action == Message.Action.Broadcast) {
            nettyChannelNodeManager.writeAndFlush(new TextWebSocketFrame(text));
        } else {
            logger.warn("> Not support message action [ message = {} ]", text);
        }

    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        Channel incoming = ctx.channel();
        logger.info("> Channel [ id = {} ] active", incoming.id());
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        nettyChannelNodeManager.removeChannel(ctx.channel());
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        Channel incoming = ctx.channel();
        logger.error("> Channel [ id = {} ] exception", incoming.id());
        // 当出现异常就关闭连接
        logger.error(StringUtils.printStackTrace(cause));
        ctx.close();
    }

    public void setNettyChannelNodeManager(NettyChannelNodeManager nettyChannelNodeManager) {
        this.nettyChannelNodeManager = nettyChannelNodeManager;
    }
}
